#ifndef __M_SELECT_H__
#define __M_SELECT_H__
#include"tcpsocket.hpp"
#include<sys/select.h>
#include<vector>

class Select{
    private:
        fd_set _rfds;
        int _max_fd;
    public:
        Select():_max_fd(-1){
            FD_ZERO(&_rfds);
        }
        //添加描述符的监控
        bool Add(TcpSocket &sock){
            //FD_SET(fd.set);
            //1.添加监控
            FD_SET(sock.FD(),&_rfds);
            //2.重新设置最大的描述符
            _max_fd = _max_fd>sock.FD()?_max_fd:sock.FD();
            return true;
        }
        //移除描述符的监控
        bool Del(TcpSocket &sock){
            //从集合移除指定描述符
            FD_CLR(sock.FD(),&_rfds);
            //更新最大描述符--移除后，从max_fd开始向前判断，还在集合中的就是最大的
            for(int i = _max_fd;i>=0;i--){
                if(FD_ISSET(i,&_rfds)){
                    _max_fd = i;
                    break;
                }
            }
            return true;
        }
        //开始监控,返回就绪的套接字数组
        bool Wait(std::vector<TcpSocket> &ready,int timeout = 3){
            //1.定义事件结构
            struct timeval tv = {.tv_sec = timeout,.tv_usec = 0};
            //2.开始监控
            fd_set tmp = _rfds;
            int ret = select(_max_fd+1,&tmp,nullptr,nullptr,&tv);
            if(ret<0){
                perror("select error");
                return false;
            }else if(ret == 0){
                std::cout<<"select timeout!\n";
                ready.clear();
                return true;
            }
            //3.遍历集合，找出就绪的描述符
            for(int i = 0;i<=_max_fd;i++){
                if(FD_ISSET(i,&tmp)){
                    TcpSocket sock(i);
                    ready.push_back(std::move(sock));
                }
            }
            return true;
        }
};


#endif